﻿using System;
using System.ComponentModel;
using System.IO;
using System.Collections.Generic;
using System.IO.Compression;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using System.Data.Common;
using System.Data;
using MYTech.Data;

namespace MYTech.Utils
{
    public interface ITranslater
    {
        string DependFieldName { get; }
        int DependFieldIndex { get; set; }
    }

    /// <summary>
    /// 进度状态报告
    /// </summary>
    /// <param name="status"></param>
    /// <returns></returns>
    public delegate bool ReportProgressStatus(string status);

    /// <summary>
    /// 进度行数报告
    /// </summary>
    /// <param name="count"></param>
    /// <returns></returns>
    public delegate bool ReportProgressConut(int count);

    /// <summary>
    /// 读取行
    /// </summary>
    /// <param name="dataReader"></param>
    /// <returns></returns>
    public delegate bool OnRead(DbDataReader dataReader);

    /// <summary>
    /// 工具类
    /// </summary>
    public class Utils
    {
        /// <summary>
        /// 二分法查找
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="obj"></param>
        /// <param name="compare"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public static bool BinarySearch<T>(List<T> list, T obj, Comparison<T> compare, out int index)
        {
            int first = 0;
            int ret = 0;
            for (int count = list.Count; count > 0; )
            {
                int count2 = count / 2;
                int mid = first + count2;
                ret = compare(list[mid], obj);
                if (ret < 0)
                {
                    first = mid + 1;
                    count -= count2 + 1;
                }
                else if (ret > 0)
                    count = count2;
                else
                {
                    index = mid;
                    return true;
                }
            }
            index = first;
            return false;
        }

        public static int LowerBound<T>(List<T> list, T obj, Comparison<T> compare)
        {
            int first = 0;
            for (int count = list.Count; count > 0; )
            {
                int count2 = count / 2;
                int mid = first + count2;
                if (compare(list[mid], obj) < 0)
                {
                    first = mid + 1;
                    count -= count2 + 1;
                }
                else
                    count = count2;
            }
            return first;
        }

        /// <summary>
        /// 运行后台操作
        /// </summary>
        /// <param name="backgroundWorker"></param>
        /// <param name="doWork"></param>
        /// <param name="runComplete"></param>
        public static void RunBackgroundWorker(BackgroundWorker backgroundWorker, DoWorkEventHandler doWork, RunWorkerCompletedEventHandler runComplete)
        {
            ClearEventHandler(backgroundWorker, "doWorkKey");
            ClearEventHandler(backgroundWorker, "runWorkerCompletedKey");
            backgroundWorker.WorkerReportsProgress = false;
            backgroundWorker.DoWork += doWork;
            backgroundWorker.RunWorkerCompleted += runComplete;
            backgroundWorker.RunWorkerAsync();
        }

        /// <summary>
        /// 运行后台操作
        /// </summary>
        /// <param name="backgroundWorker"></param>
        /// <param name="doWork"></param>
        /// <param name="reportProgress"></param>
        /// <param name="runComplete"></param>
        public static void RunBackgroundWorker(BackgroundWorker backgroundWorker, DoWorkEventHandler doWork, ProgressChangedEventHandler reportProgress, RunWorkerCompletedEventHandler runComplete)
        {
            ClearEventHandler(backgroundWorker, "doWorkKey");
            ClearEventHandler(backgroundWorker, "progressChangedKey");
            ClearEventHandler(backgroundWorker, "runWorkerCompletedKey");
            backgroundWorker.WorkerReportsProgress = true;
            backgroundWorker.DoWork += doWork;
            backgroundWorker.ProgressChanged += reportProgress;
            backgroundWorker.RunWorkerCompleted += runComplete;
            backgroundWorker.RunWorkerAsync();
        }

        public static void ClearEventHandler(Component obj, string eventName)
        {
            Type t = obj.GetType();
            EventHandlerList eventHandlerList = (EventHandlerList)t.InvokeMember("Events", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty, null, obj, null);
            object key = t.InvokeMember(eventName, BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField, null, null, null);
            Delegate eventDelegate = eventHandlerList[key];
            if (eventDelegate != null)
            {
                foreach (Delegate invocation in eventDelegate.GetInvocationList())
                {
                    eventHandlerList.RemoveHandler(key, invocation);
                }
            }
        }

        public static object InvokeStaticMember(Type type, string methodName)
        {
            return InvokeStaticMember(type, methodName, null);
        }

        public static object InvokeStaticMember(Type type, string methodName, object[] param)
        {
            return type.InvokeMember(methodName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.InvokeMethod, null, null, param);
        }

        /// <summary>
        /// 跨线程设置控件属性值委托类型定义
        /// </summary>
        /// <param name="flag"></param>
        /// <param name="obj"></param>
        /// <param name="methodName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static object InvokeMember(BindingFlags flag, object obj, string methodName, object[] value)
        {
            return obj.GetType().InvokeMember(methodName, BindingFlags.Public | BindingFlags.Instance | flag, null, obj, value);
        }

        private delegate object InvokeMemberCallBack(BindingFlags flag, object obj, string methodName, object[] value);
        /// <summary>
        /// 跨线程设置控件属性值委托类型定义
        /// </summary>
        public static object InvokeMember(BindingFlags flag, Control control, string name, object[] value)
        {
            if (control.InvokeRequired == true)
                return control.Invoke(new InvokeMemberCallBack(InvokeMember), new object[] { flag, control, name, value });
            else
                return InvokeMember(flag, (object)control, name, value);
        }

        /// <summary>
        /// 跨线程设置控件属性值
        /// </summary>
        public static void PropertySet(Control control, string name, object value)
        {
            InvokeMember(BindingFlags.SetProperty, control, name, new object[] { value });
        }

        /// <summary>
        /// 跨线程读取控件属性值
        /// </summary>
        public static object PropertyGet(Control control, string name)
        {
            return InvokeMember(BindingFlags.GetProperty, control, name, null);
        }

        public delegate void SimpleCallBack();
        public static void Invoke(Control control, SimpleCallBack func)
        {
            if (control.InvokeRequired)
                control.Invoke(new SimpleCallBack(func));
            else
                func();
        }

        /// <summary>
        /// 直接通过SQL语句导出数据到文件中
        /// </summary>
        /// <param name="savePath"></param>
        /// <param name="columns"></param>
        /// <param name="formatters"></param>
        /// <param name="sqlStr"></param>
        /// <param name="append">为true时表示连接上一次导出的相同文件名的文件之后</param>
        /// <returns></returns>
        public static int ExportSQLData(string savePath, string columns, ICustomFormatter[] formatters, string sqlStr, bool append)
        {
            int rowCount = 0;
            StreamWriter sw = null;
            try
            {
                string[] columnValues = null;
                MYTech.Oracle.DataHelper.ExecuteNonQuery(sqlStr, dataReader =>
                 {
                     sw = new StreamWriter(savePath, append, Encoding.Default, 128 * 1024);
                     string[] fieldNames = new string[dataReader.FieldCount];
                     columnValues = new string[fieldNames.Length];
                     for (int i = 0; i < fieldNames.Length; i++)
                         fieldNames[i] = dataReader.GetName(i);
                     if (formatters != null)
                     {
                         for (int i = 0; i < fieldNames.Length; i++)
                         {
                             ICustomFormatter formatter = formatters[i];
                             if (formatter != null && (formatter is ITranslater))
                                 ((ITranslater)formatter).DependFieldIndex = Array.IndexOf(fieldNames, ((ITranslater)formatter).DependFieldName);
                         }
                     }
                     if (!append)
                     {
                         if (columns == null)
                         {
                             sw.Write('\"');
                             sw.Write(string.Join("\",\"", fieldNames));
                             sw.Write("\"\n");
                         }
                         else
                             sw.WriteLine(columns);
                     }
                     return true;
                 }, dataReader =>
                 {
                     if (formatters == null)
                     {
                         for (int i = 0; i < dataReader.FieldCount; i++)
                             columnValues[i] = dataReader[i].ToString();
                     }
                     else
                     {
                         for (int i = 0; i < dataReader.FieldCount; i++)
                         {
                             if (i >= formatters.Length || formatters[i] == null)
                                 columnValues[i] = dataReader[i].ToString();
                             else
                             {
                                 int fieldIndex = i;
                                 ICustomFormatter formatter = formatters[i];
                                 if (formatter is ITranslater)
                                     fieldIndex = ((ITranslater)formatter).DependFieldIndex;
                                 object data = dataReader[fieldIndex];
                                 columnValues[i] = (data != DBNull.Value) ? formatters[i].Format(null, data, null) : null;
                             }
                         }
                     }
                     sw.Write('\"');
                     sw.Write(string.Join("\",\"", columnValues));
                     sw.Write("\"\n");
                     ++rowCount;
                     return true;
                 });
            }
            catch (Exception ex)
            {
                ExceptionManager.TraceWrite(ex);
                rowCount = -1;
            }
            finally
            {
                if (sw != null)
                    sw.Close();
            }
            return rowCount;
        }

        /// <summary>
        /// 直接通过SQL语句导出数据到文件中
        /// </summary>
        /// <param name="savePath"></param>
        /// <param name="sqlStr"></param>
        /// <returns></returns>
        public static int ExportSQLData(string savePath, string sqlStr)
        {
            return ExportSQLData(savePath, sqlStr, false);
        }

        /// <summary>
        /// 直接通过SQL语句导出数据到文件中
        /// </summary>
        /// <param name="savePath"></param>
        /// <param name="sqlStr"></param>
        /// <param name="append">为true时表示连接上一次导出的相同文件名的文件之后</param>
        /// <returns></returns>
        public static int ExportSQLData(string savePath, string sqlStr, bool append)
        {
            return ExportSQLData(savePath, null, null, sqlStr, append);
        }

        /// <summary>
        /// 直接通过SQL语句导出数据到文件中
        /// </summary>
        /// <param name="savePath"></param>
        /// <param name="columns"></param>
        /// <param name="sqlStr"></param>
        /// <returns></returns>
        public static int ExportSQLData(string savePath, string columns, string sqlStr)
        {
            return ExportSQLData(savePath, columns, null, sqlStr, false);
        }

        /// <summary>
        /// 直接通过SQL语句导出数据到文件中
        /// </summary>
        /// <param name="savePath"></param>
        /// <param name="columns"></param>
        /// <param name="formatters"></param>
        /// <param name="sqlStr"></param>
        /// <returns></returns>
        public static int ExportSQLData(string savePath, string columns, ICustomFormatter[] formatters, string sqlStr)
        {
            return ExportSQLData(savePath, columns, formatters, sqlStr, false);
        }
    }
}
